#include "MiniBSplineCurveHandler.h"

MiniBSplineCurveHandler::MiniBSplineCurveHandler(MiniObject *obj)
    : MiniHandler(obj)
{
    UpdateHandler();
}

float MiniBSplineCurveHandler::CheckCollision(QPointF pos, QMatrix4x4 projection)
{
    MiniBSplineCurve *spline = (MiniBSplineCurve*)m_object;

    // 第一个数组存放顶点信息
    int n = spline->GetPointsNum();
    MiniArray<Vector3f> &vertices = spline->GetPoints();
    for (int i = 0; i < n; i++)
    {
        QVector4D v = projection * QVector4D{vertices[i].x(), vertices[i].y(), vertices[i].z(), 1};
        v = v / v.w();

        // 如果拾取到，返回 z 坐标判断深度
        if ((QPointF{v.x(), v.y()} - pos).manhattanLength() < 0.01)
        {
            m_vertex = &vertices.at(i);
            return v.z();
        }
    }
    return 1;
}

void MiniBSplineCurveHandler::ChangeVertex(Vector3f dv)
{
    if (m_vertex != nullptr)
        *m_vertex = *m_vertex + dv;
    UpdateHandler();
}

void MiniBSplineCurveHandler::UpdateHandler()
{
    InitHandler();
    LoadSpline();
    LoadCptPoly();
    LoadCpts();
}

void MiniBSplineCurveHandler::LoadSpline()
{
    // 转化为 B 样条类型
    MiniBSplineCurve *spline = (MiniBSplineCurve*)m_object;

    Real bu = spline->GetBegin();
    Real eu = spline->GetEnd();
    float* vertices = new float[1000 * 3];
    unsigned int* indices = new unsigned int[1000];
    for (int i = 0; i < 1000; i++)
    {
        indices[i] = i;
        Vector3f p = spline->CurvePoint(bu + (eu - bu) / 999 * i);
        vertices[i * 3 + 0] = p.x();
        vertices[i * 3 + 1] = p.y();
        vertices[i * 3 + 2] = p.z();
    }

    // 储存数据
    m_countIndices.push_back(1000);
    m_countVertices.push_back(1000);
    m_vertices.push_back(vertices);
    m_indices.push_back(indices);
    m_modes.push_back(GL_LINE_STRIP);
    m_color.push_back(m_basisColor);
    m_lineWidth.push_back(2);
}

void MiniBSplineCurveHandler::LoadCptPoly()
{
    // 转化为 B 样条类型
    MiniBSplineCurve *spline = (MiniBSplineCurve*)m_object;

    // 推入控制点
    const MiniArray<Vector3f> &cpts = spline->GetPoints();
    float* vertices = new float[cpts.size() * 3];
    unsigned int* indices = new unsigned int[cpts.size()];
    for (int i = 0; i < int(cpts.size()); i++)
    {
        indices[i] = i;
        vertices[i * 3 + 0] = cpts[i].x();
        vertices[i * 3 + 1] = cpts[i].y();
        vertices[i * 3 + 2] = cpts[i].z();
    }

    // 储存数据
    m_countIndices.push_back(cpts.size());
    m_countVertices.push_back(cpts.size());
    m_vertices.push_back(vertices);
    m_indices.push_back(indices);
    m_modes.push_back(GL_LINE_STRIP);
    m_color.push_back({0.3, 0.3, 0.3});
    m_lineWidth.push_back(1);
}

void MiniBSplineCurveHandler::LoadCpts()
{
    // 转化为 B 样条类型
    MiniBSplineCurve *spline = (MiniBSplineCurve*)m_object;

    // 推入控制点
    const MiniArray<Vector3f> &cpts = spline->GetPoints();
    float* vertices = new float[cpts.size() * 3];
    unsigned int* indices = new unsigned int[cpts.size()];
    for (int i = 0; i < int(cpts.size()); i++)
    {
        indices[i] = i;
        vertices[i * 3 + 0] = cpts[i].x();
        vertices[i * 3 + 1] = cpts[i].y();
        vertices[i * 3 + 2] = cpts[i].z();
    }

    // 储存数据
    m_countIndices.push_back(cpts.size());
    m_countVertices.push_back(cpts.size());
    m_vertices.push_back(vertices);
    m_indices.push_back(indices);
    m_modes.push_back(GL_POINTS);
    m_color.push_back({0.6, 0.6, 0.6});
    m_lineWidth.push_back(1);
}
